package org.opens.javaskill.design.apply;

import java.util.LinkedList;

/**
 * 说明:
 * <pre>
 *     1. 这个设计模式叫做-接受异步消息的主动方法;
 * </pre>
 * @Date 2020/9/28 21:51
 * @Created by 99126
 */
public class ActiveObjectsPattern {

    public static void main(String[] args) {
        ActiveObject activeObject = ActiveObjectFactory.createActiveObject();
        new MakerClientThread("alice", activeObject).start();
        new MakerClientThread("bobby", activeObject).start();

        new DisplayClientThread("chris", activeObject).start();
    }

    static class DisplayMethodTest {

        public static void main(String[] args) {

        }

    }

}

/**
 * 说明:
 * <pre>
 *     1. 生产者消费者模式中的生产者;
 *      - 向ActiveObject的ActivationQueue中生产对象;
 * </pre>
 */
class MakerClientThread extends Thread {

    private final ActiveObject activeObject;

    private final char fillChar;

    public MakerClientThread(String name, ActiveObject activeObject) {
        super(name);
        this.activeObject = activeObject;
        this.fillChar = name.charAt(0);
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            Result result = activeObject.makeString(i, this.fillChar);
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String value = (String) result.getResultValue();
            System.out.println(Thread.currentThread().getName() + ": value = " + value);
        }
    }
}

/**
 * 说明:
 * <pre>
 *     1. 生产者消费者模式中的消费者;
 *      - 从ActiveObject的ActivationQueue中消费对象;
 * </pre>
 */
class DisplayClientThread extends Thread {

    private final ActiveObject activeObject;

    public DisplayClientThread(String name, ActiveObject activeObject) {
        super(name);
        this.activeObject = activeObject;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            String nameNumber = Thread.currentThread().getName() + " " + i;
            activeObject.displayString(nameNumber);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

interface ActiveObject {

    Result makeString(int count, char fillChar);

    void displayString(String text);

}

/**
 * 说明:
 * <pre>
 *     1. 对ActiveObject方法的调用进行封装并立即返回, 不陷入阻塞;
 *     2. 使用了静态代理;
 * </pre>
 */
class ActiveObjectProxy implements ActiveObject {

    private final SchedulerThread schedulerThread;

    private final Servant servant;

    public ActiveObjectProxy(SchedulerThread schedulerThread, Servant servant) {
        this.schedulerThread = schedulerThread;
        this.servant = servant;
    }

    @Override
    public Result makeString(int count, char fillChar) {
        FutureResult futureResult = new FutureResult();
        schedulerThread.invoke(new MakeStringRequest(servant, futureResult, count, fillChar));
        return futureResult;
    }

    @Override
    public void displayString(String text) {
        this.schedulerThread.invoke(new DisplayStringRequest(servant, text));
    }
}

/**
 * 说明:
 * <pre>
 *     1. 实际应用中, 要求ActiveObjectProxy是限定包范围的, 不能在包之外new, 所以提供一个工厂进行创建;
 * </pre>
 */
final class ActiveObjectFactory {

    private ActiveObjectFactory() {}

    public static ActiveObject createActiveObject() {
        // 定义真正的方法逻辑
        Servant servant = new Servant();
        // 定义任务队列
        ActivationQueue activationQueue = new ActivationQueue();
        // 定义
        SchedulerThread schedulerThread = new SchedulerThread(activationQueue);
        ActiveObjectProxy activeObjectProxy = new ActiveObjectProxy(schedulerThread, servant);
        schedulerThread.start();
        return activeObjectProxy;
    }

}

/**
 * 说明:
 * <pre>
 *     1. 对应{@link ActiveObject}类的每一个方法.
 * </pre>
 */
abstract class MethodRequest {

    protected final Servant servant;

    protected final FutureResult futureResult;

    public MethodRequest(Servant servant, FutureResult futureResult) {
        this.servant = servant;
        this.futureResult = futureResult;
    }

    public abstract void execute();

}

/**
 * 说明:
 * <pre>
 *     1. {@link ActiveObject#makeString(int, char)}方法的抽象类;
 *     2. 使用了模板设计模式;
 * </pre>
 */
class MakeStringRequest extends MethodRequest {

    private final int count;

    private final char fillChar;

    public MakeStringRequest(Servant servant, FutureResult futureResult, int count, char fillChar) {
        super(servant, futureResult);
        this.count = count;
        this.fillChar = fillChar;
    }

    @Override
    public void execute() {
        // 这里会对真正的业务逻辑执行者Servant的方法进行调用
        Result result = servant.makeString(count, fillChar);
        futureResult.setResult(result);
    }

}

/**
 * 说明:
 * <pre>
 *     1. 使用了模板设计模式;
 * </pre>
 */
class DisplayStringRequest extends MethodRequest {

    private final String text;

    public DisplayStringRequest(Servant servant, String text) {
        super(servant, null);
        this.text = text;
    }

    @Override
    public void execute() {
        this.servant.displayString(this.text);
    }

}

/**
 * 说明:
 * <pre>
 *     1. 真正的干活者;
 * </pre>
 */
class Servant implements ActiveObject {

    @Override
    public Result makeString(int count, char fillChar) {
        char[] buffer = new char[count];
        for (int i = 0; i < count; i++) {
            buffer[i] = fillChar;
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return new RealResult(new String(buffer));
    }

    @Override
    public void displayString(String text) {
        System.out.println("display" + text);
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

/**
 * 说明:
 * <pre>
 *     1. {@link ActiveObject}类的函数的运行结果的抽象;
 * </pre>
 */
interface Result {

    Object getResultValue();

}

/**
 * 说明:
 * <pre>
 *     1. {@link ActiveObject#displayString(String)}同步结果封装;
 * </pre>
 */
class RealResult implements Result {

    private final Object objectValue;

    public RealResult(Object objectValue) {
        this.objectValue = objectValue;
    }

    @Override
    public synchronized Object getResultValue() {
        return this.objectValue;
    }
}

/**
 * 说明:
 * <pre>
 *     1. {@link ActiveObject#makeString(int, char)}异步结果封装;
 * </pre>
 */
class FutureResult implements Result {

    private Result result;

    private boolean ready = false;

    public synchronized void setResult(Result result) {
        this.result = result;
        this.ready = true;
        this.notifyAll();
    }

    /**
     * 说明:
     * <pre>
     *     1. 如果当前FutureResult还没有处理完毕, 就先使当前线程休眠;
     * </pre>
     */
    @Override
    public synchronized Object getResultValue() {
        while(!ready) {
            try {
                // 如果当前未准备好, 则使当前线程睡眠.
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return this.result.getResultValue();
    }
}

/**
 * 说明:
 * <pre>
 *     1. 任务队列, 存储调用者发起的请求.
 * </pre>
 */
class ActivationQueue {

    private final static int MAX_QUEUE_SIZE = 100;

    private final LinkedList<MethodRequest> methodQueue;

    public ActivationQueue() {
        this.methodQueue = new LinkedList<>();;
    }

    public synchronized void put(MethodRequest methodRequest) {
        while (this.methodQueue.size() > MAX_QUEUE_SIZE) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.methodQueue.addLast(methodRequest);
        this.notifyAll();
    }

    public synchronized MethodRequest take() {
        while (this.methodQueue.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        MethodRequest methodRequest = this.methodQueue.removeFirst();
        return methodRequest;
    }

}

/**
 * 说明:
 * <pre>
 *     1. 任务队列的单独工作线程封装;
 * </pre>
 */
class SchedulerThread extends Thread {

    private final ActivationQueue activationQueue;

    public SchedulerThread(ActivationQueue activationQueue) {
        this.activationQueue = activationQueue;
    }

    public void invoke(MethodRequest methodRequest) {
        this.activationQueue.put(methodRequest);
    }

    @Override
    public void run() {
        while (true) {
            activationQueue.take().execute();
        }
    }
}